package com.jp;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;

import java.util.Objects;

public class IntervalSelector extends View {
    private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    final My my;
    private final Rect tempRect = new Rect();
    private GenericCallback<Boolean, Void, Void, Void> selectedListener;

    public IntervalSelector(Context context) {
        super(context);
        my = init(null);
    }

    public IntervalSelector(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        my = init(attrs);
    }

    public IntervalSelector(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        my = init(attrs);
    }

    private My init(@Nullable AttributeSet attrs) {
        return new My(getContext(), attrs);
    }

    public void setSelectedListener(GenericCallback<Boolean, Void, Void, Void> selectedListener) {
        this.selectedListener = selectedListener;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        my.init(this);
    }


    private float lastX;

    private final GenericCallback<My, Float, Void, Void> moveLeftSlider = (GenericCallback<My, Float, Void, Void>) (my, offsetX, aVoid) -> {
        if (my == null || offsetX == null) return null;
        final float rawDestinationX = my.mDestRect.centerX() + offsetX;

        final float curRCoordinate = my.getCoordinateByValue(my.curRValue);
        final float destinationX = Math.max(Math.min(rawDestinationX, curRCoordinate), my.leftSliderEdgeCenterX);


        my.mDestRect.offsetTo(destinationX - my.lsw / 2f, my.mDestRect.top);
        my.curLValue = my.getValueByX(Math.round(my.mDestRect.centerX()));
        return null;
    };
    private final GenericCallback<My, Float, Void, Void> moveRightSlider = (GenericCallback<My, Float, Void, Void>) (my, offsetX, aVoid) -> {
        if (my == null || offsetX == null) return null;
        final float rawDestinationX = my.mDestRectRight.centerX() + offsetX;
        final float curLCoordinate = my.getCoordinateByValue(my.curLValue);
        final float destinationX = Math.min(Math.max(rawDestinationX, curLCoordinate), my.rightSliderEdgeCenterX);

        my.mDestRectRight.offsetTo(destinationX - my.rsw / 2f, my.mDestRectRight.top);
        my.curRValue = my.getValueByX(Math.round(my.mDestRectRight.centerX()));
        return null;
    };
    private GenericCallback<My, Float, Void, Void> moveSlider;
    private GenericCallback<My, Void, Void, Void> tuningSlider;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final float curX = event.getX(), curY = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = curX;
                final boolean result = my.mDestRect.contains(curX, curY) || my.mDestRectRight.contains(curX, curY);
                final boolean downEventOnLeft = RangeSelectionView2RectFHelper.ownL(my.mDestRect, my.mDestRectRight, curX);
                final boolean bothLeft = my.L != null && my.R != null && my.curLValue == my.L && my.curRValue == my.L;
                final boolean bothRight = my.L != null && my.R != null && my.curLValue == my.R && my.curRValue == my.R;
                moveSlider = downEventOnLeft ? (bothLeft ? moveRightSlider : moveLeftSlider) : (bothRight ? moveLeftSlider : moveRightSlider);
                tuningSlider = downEventOnLeft ? (bothLeft ? RangeSelectionView2RectFHelper.tuningRightSlider : RangeSelectionView2RectFHelper.tuningLeftSlider)
                        : (bothRight ? RangeSelectionView2RectFHelper.tuningLeftSlider : RangeSelectionView2RectFHelper.tuningRightSlider);
                return result;
            case MotionEvent.ACTION_MOVE:
                final float offsetX = curX - lastX;
                moveSlider.onCall(my, offsetX, null);

                invalidate();
//                my.curL
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:


                tuningSlider.onCall(my, null, null);
                invalidate();
                break;
        }

        lastX = curX;
        if (selectedListener != null)
            selectedListener.onCall(my.L != null && my.R != null && (my.curLValue != my.L || my.curRValue != my.R), null, null);
        return super.onTouchEvent(event);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        RangeSelectionView2DrawHelper.drawBgLine(getContext(), canvas, paint, my);
        RangeSelectionView2DrawHelper.drawLine(getContext(), canvas, paint, my);
        RangeSelectionView2DrawHelper.drawSlider(canvas, paint, my);
        RangeSelectionView2DrawHelper.drawSliderText(getContext(), canvas, paint, my, tempRect);
    }


    public static final class My {
        // 区间左边界值
        Integer L;
        // 区间右边界值
        Integer R;
        final String unit;
        // 一单位数值几个像素
        float step;
        // 滑块中心横坐标
        int leftSliderEdgeCenterX, rightSliderEdgeCenterX;

        int centerY;
        // 左右滑块宽高，lsw - left slider width
        final int lsw, lsh, rsw, rsh;
        public final Bitmap mSrcBitmap;
        public final Bitmap mSrcBitmapRight;

        public final Rect mSrcRect;
        public final RectF mDestRect;
        public final Rect mSrcRectRight;
        public final RectF mDestRectRight;

        int curLValue = Integer.MIN_VALUE, curRValue = Integer.MIN_VALUE;
        Integer applyLValue, applyRValue;
        public final int lineBg, lineFg, lineHeight, textColor, textSize;

        public My(Context context, @Nullable AttributeSet attrs) {

            // todo
            this.unit = "$";


            final TypedArray a = context.obtainStyledAttributes(attrs, com.jp.R.styleable.IntervalSelector);
            final int ldw = a.getDimensionPixelSize(com.jp.R.styleable.IntervalSelector_IntervalSelector_l_drawable_width, 60);
            final int ldh = a.getDimensionPixelSize(com.jp.R.styleable.IntervalSelector_IntervalSelector_l_drawable_height, 60);
            final int rdw = a.getDimensionPixelSize(com.jp.R.styleable.IntervalSelector_IntervalSelector_r_drawable_width, 60);
            final int rdh = a.getDimensionPixelSize(com.jp.R.styleable.IntervalSelector_IntervalSelector_r_drawable_height, 60);
            mSrcBitmap = Bitmap.createBitmap(ldw, ldh, Bitmap.Config.ARGB_8888);
            try {
                final Drawable drawable = ContextCompat.getDrawable(context, a.getResourceId(com.jp.R.styleable.IntervalSelector_IntervalSelector_leftDrawable, com.jp.R.drawable.slider));
                Objects.requireNonNull(drawable).setBounds(0, 0, ldw, ldh);
                Objects.requireNonNull(drawable).draw(new Canvas(mSrcBitmap));
            } catch (Exception e) {
                e.printStackTrace();
            }
            mSrcBitmapRight = Bitmap.createBitmap(rdw, rdh, Bitmap.Config.ARGB_8888);
            try {
                final Drawable drawable = ContextCompat.getDrawable(context, a.getResourceId(com.jp.R.styleable.IntervalSelector_IntervalSelector_rightDrawable, com.jp.R.drawable.slider));
                Objects.requireNonNull(drawable).setBounds(0, 0, rdw, rdh);
                Objects.requireNonNull(drawable).draw(new Canvas(mSrcBitmapRight));
            } catch (Exception e) {
                e.printStackTrace();
            }
//            mSrcBitmap = BitmapFactory.decodeResource(context.getResources(), a.getResourceId(com.jp.R.styleable.IntervalSelector_IntervalSelector_leftDrawable, com.jp.R.drawable.slider));
//            mSrcBitmapRight = BitmapFactory.decodeResource(context.getResources(), a.getResourceId(com.jp.R.styleable.IntervalSelector_IntervalSelector_rightDrawable, com.jp.R.drawable.slider));
            this.lsw = mSrcBitmap.getWidth();
            this.lsh = mSrcBitmap.getHeight();
            this.rsw = mSrcBitmapRight.getWidth();
            this.rsh = mSrcBitmapRight.getHeight();
            mSrcRect = new Rect(0, 0, lsw, lsh);
            mDestRect = new RectF(-lsw, -lsh, 0, 0);

            mSrcRectRight = new Rect(0, 0, rsw, rsh);
            mDestRectRight = new RectF(-rsw, -rsh, 0, 0);
            this.lineBg = a.getColor(com.jp.R.styleable.IntervalSelector_IntervalSelector_line_bg, Color.BLACK);
            this.lineFg = a.getColor(com.jp.R.styleable.IntervalSelector_IntervalSelector_line_fg, Color.WHITE);
            this.lineHeight = a.getDimensionPixelSize(com.jp.R.styleable.IntervalSelector_IntervalSelector_line_height, 0);

            this.textColor = a.getColor(com.jp.R.styleable.IntervalSelector_IntervalSelector_text_color, Color.BLACK);
            this.textSize = a.getDimensionPixelSize(com.jp.R.styleable.IntervalSelector_IntervalSelector_text_size, 10);
            a.recycle();

        }

        void init(IntervalSelector v) {
            final int paddingL = v.getPaddingStart();
            final int paddingR = v.getPaddingEnd();
            final int width = v.getMeasuredWidth();
            if (L != null && R != null)
                step = (width - (paddingL + paddingR + lsw / 2f + rsw / 2f)) / (R - L);
            leftSliderEdgeCenterX = paddingL + Math.round(lsw / 2f);
            rightSliderEdgeCenterX = width - paddingR - Math.round(rsw / 2f);

            centerY = Math.round(v.getMeasuredHeight() / 2f);


            mDestRect.offsetTo(getCoordinateByValue(curLValue) - lsw / 2f, Math.round((v.getMeasuredHeight() - lsh) / 2f));

            mDestRectRight.offsetTo(getCoordinateByValue(curRValue) - rsw / 2f, Math.round((v.getMeasuredHeight() - rsh) / 2f));
            move2ValueCoordinate(v);
            v.invalidate();
        }

        void initStep(View v) {
            final int paddingL = v.getPaddingStart();
            final int paddingR = v.getPaddingEnd();
            final int width = v.getMeasuredWidth();
            if (L != null && R != null)
                step = (width - (paddingL + paddingR + lsw / 2f + rsw / 2f)) / (R - L);


        }

        public String getValueText(final boolean left) {
            final int value = getValueByX(Math.round((left ? mDestRect : mDestRectRight).centerX()));
            return unit + value;
        }

        /**
         * 根据坐标得数值
         */
        private int getValueByX(final int x) {
            if (L == null || R == null) return 0;
            if (x <= leftSliderEdgeCenterX) return L;
            if (x >= rightSliderEdgeCenterX) return R;
            final int rawValue = L + Math.round((x - leftSliderEdgeCenterX) / step);
            return Math.min(R, rawValue);
        }

        /**
         * 根据数值得坐标
         */
        public int getCoordinateByValue(final int value) {
            if (L == null || R == null) return 0;
            if (value <= L) return leftSliderEdgeCenterX;
            if (value >= R) return rightSliderEdgeCenterX;
            final int rawCoordinate = leftSliderEdgeCenterX + Math.round((value - L) * step);
            return Math.min(rawCoordinate, rightSliderEdgeCenterX);
        }

        public void move2ValueCoordinate(View v) {
            mDestRect.offsetTo(getCoordinateByValue(curLValue) - lsw / 2f, Math.round((v.getMeasuredHeight() - lsh) / 2f));

            mDestRectRight.offsetTo(getCoordinateByValue(curRValue) - rsw / 2f, Math.round((v.getMeasuredHeight() - rsh) / 2f));
        }

        void reset(boolean resetApplyPrice) {
            if (L == null || R == null) return;
            mDestRect.offsetTo(leftSliderEdgeCenterX - lsw / 2f, mDestRect.top);
            mDestRectRight.offsetTo(rightSliderEdgeCenterX - rsw / 2f, mDestRectRight.top);
            curLValue = L;
            curRValue = R;
            if (resetApplyPrice) {
                applyLValue = null;
                applyRValue = null;
            }

        }
    }

}
